import React, {useCallback, useDeferredValue, useEffect, useMemo, useState} from 'react'
import {Button, Input, Space, Tooltip, Tree} from 'antd'
import {
    CloudServerOutlined,
    DatabaseOutlined,
    HddOutlined,
    PlusOutlined,
    ReloadOutlined,
    TableOutlined
} from '@ant-design/icons'
import type {DatabaseType, DataSourceTreeNode} from '@/types/source'
import {sourceApi} from '@/services/api/source'

type AntTreeNode = { key: string; title: React.ReactNode; children?: AntTreeNode[] }

interface Props {
  onCreateCatalog?: () => void
  onSelectNode?: (node: DataSourceTreeNode) => void
  // 父级可改变此 key 触发重新加载树
  reloadKey?: number | string
}

const sampleData: DataSourceTreeNode[] = [
  {
    id: 'server-1',
    name: 'Server1',
    nodeType: 'SERVER',
    children: [
      {
        id: 'catalog-1',
        name: '巡检系统',
        nodeType: 'CATALOG',
        databaseType: 'MYSQL',
        enabled: true,
        children: [
          {
            id: 'db-1',
            name: 'inspection_db',
            nodeType: 'DATABASE',
            children: [
              { id: 'table-1', name: 'user_info', nodeType: 'TABLE', activeDimensionName: 'id' },
              { id: 'table-2', name: 'log_record', nodeType: 'TABLE', activeDimensionName: null }
            ]
          },
          { id: 'db-2', name: 'log_db', nodeType: 'DATABASE' }
        ]
      }
    ]
  }
]

function catalogIcon(t?: DatabaseType, disabled?: boolean) {
  const baseStyle = { marginRight: 6, verticalAlign: '-2px' } as const
  const colorMap: Record<string, string> = {
    MYSQL: '#4479A1',
    ORACLE: '#F80000',
    POSTGRESQL: '#336791',
    SQLSERVER: '#CC2927',
  }
  const color = disabled ? '#999' : (t ? colorMap[t] || '#666' : '#666')
  return <DatabaseOutlined style={{ ...baseStyle, color }} />
}

export default function DataSourceTree({ onCreateCatalog, onSelectNode, reloadKey }: Props) {
  const [displayServer, setDisplayServer] = useState(true)
  const [displayTable, setDisplayTable] = useState(false)
  const [searchRaw, setSearchRaw] = useState('')
  const searchValue = useDeferredValue(searchRaw)
  const [selectedKeys, setSelectedKeys] = useState<string[]>([])
  const [raw, setRaw] = useState<DataSourceTreeNode[]>([])
  const [loading, setLoading] = useState(false)

  const fetchTree = useCallback(async () => {
    setLoading(true)
    try {
      const data = await sourceApi.getTree(displayServer, displayTable)
      setRaw(data || [])
    } catch (e) {
      console.error(e)
      setRaw([])
    } finally {
      setLoading(false)
    }
  }, [displayServer, displayTable])

  useEffect(() => {
    fetchTree()
  }, [fetchTree, reloadKey])

  const filterByFlags = useCallback((nodes: DataSourceTreeNode[]): DataSourceTreeNode[] => {
    const visit = (arr: DataSourceTreeNode[]): DataSourceTreeNode[] => {
      const result: DataSourceTreeNode[] = []
      for (const n of arr) {
        const nodeType = n.nodeType || n.type
        let children = n.children ? visit(n.children) : undefined
        if (!displayTable && children) {
          children = children.filter((c) => (c.nodeType || c.type) !== 'TABLE')
        }
        const next = { ...n, children }
        if (!displayServer && nodeType === 'SERVER') {
          if (children) result.push(...children)
        } else {
          result.push(next)
        }
      }
      return result
    }
    return visit(nodes)
  }, [displayServer, displayTable])

  const sortOrder: Record<string, number> = { SERVER: 0, CATALOG: 1, DATABASE: 2, TABLE: 3 }
  const sortNodes = useCallback((arr: DataSourceTreeNode[]): DataSourceTreeNode[] => {
    const sorted = [...arr].sort((a, b) => {
      const ta = (a.nodeType || a.type) as string
      const tb = (b.nodeType || b.type) as string
      const oa = sortOrder[ta] ?? 99
      const ob = sortOrder[tb] ?? 99
      if (oa !== ob) return oa - ob
      return a.name.localeCompare(b.name)
    })
    return sorted.map((n) => ({ ...n, children: n.children ? sortNodes(n.children) : undefined }))
  }, [])

  const matches = useCallback((name: string) => {
    if (!searchValue) return true
    return name.toLowerCase().includes(searchValue.toLowerCase())
  }, [searchValue])

  const filtered = useMemo(() => {
    const recur = (arr: DataSourceTreeNode[]): DataSourceTreeNode[] => {
      return arr
        .map((n) => ({ ...n, children: n.children ? recur(n.children) : undefined }))
        .filter((n) => {
          const childrenMatch = (n.children || []).length > 0
          return matches(n.name) || childrenMatch
        })
    }
    return sortNodes(recur(filterByFlags(raw)))
  }, [raw, filterByFlags, matches, sortNodes])

  const renderName = useCallback((name: string): React.ReactNode => {
    if (!searchValue) return name
    const idx = name.toLowerCase().indexOf(searchValue.toLowerCase())
    if (idx === -1) return name
    const before = name.slice(0, idx)
    const match = name.slice(idx, idx + searchValue.length)
    const after = name.slice(idx + searchValue.length)
    return (
      <>
        {before}
        <span style={{ background: '#ffe58f' }}>{match}</span>
        {after}
      </>
    )
  }, [searchValue])

  const renderTitle = useCallback((n: DataSourceTreeNode): React.ReactNode => {
    const nodeType = n.nodeType || n.type
    const isCatalog = nodeType === 'CATALOG'
    const isTable = nodeType === 'TABLE'
    const isDisabled = isCatalog && n.enabled === false
    const isBrokenTable = isTable && (n.activeDimensionName == null)
    const color = isBrokenTable ? 'red' : isDisabled ? '#999' : undefined
    const weight = searchValue && n.name.toLowerCase().includes(searchValue.toLowerCase()) ? 600 : 400
    return (
      <span style={{ color, fontWeight: weight }}>
        {nodeType === 'SERVER' && <CloudServerOutlined style={{ marginRight: 6, color: '#666', verticalAlign: '-2px' }} />}
        {nodeType === 'CATALOG' && catalogIcon(n.databaseType, isDisabled)}
        {nodeType === 'DATABASE' && <HddOutlined style={{ marginRight: 6, color: '#666', verticalAlign: '-2px' }} />}
        {nodeType === 'TABLE' && <TableOutlined style={{ marginRight: 6, color: isBrokenTable ? 'red' : '#666', verticalAlign: '-2px' }} />}
        {renderName(n.name)}
      </span>
    )
  }, [searchValue, renderName])

  const toAntTree = useCallback((arr: DataSourceTreeNode[]): AntTreeNode[] => {
    return arr.map((n) => ({
      key: n.id,
      title: renderTitle(n),
      children: n.children ? toAntTree(n.children) : undefined,
    }))
  }, [renderTitle])

  const treeData = useMemo(() => toAntTree(filtered), [filtered, toAntTree])

  const onSelect = useCallback((_keys: React.Key[], info: any) => {
    const k = String(info.node.key)
    setSelectedKeys([k])
    // 找到原始节点路径链，并填充父级信息便于右侧视图调用接口
    const findPath = (arr: DataSourceTreeNode[], targetId: string, path: DataSourceTreeNode[] = []): DataSourceTreeNode[] | undefined => {
      for (const item of arr) {
        const nextPath = [...path, item]
        if (item.id === targetId) return nextPath
        if (item.children) {
          const sub = findPath(item.children, targetId, nextPath)
          if (sub) return sub
        }
      }
      return undefined
    }
    const path = findPath(raw, k)
    const node = path ? path[path.length - 1] : undefined
    if (node && onSelectNode) {
      const typeOf = (n: DataSourceTreeNode) => String(n.nodeType || (n as any).type || '').toUpperCase()
      const reversed = [...(path || [])].reverse()
      const catalog = reversed.find((n) => typeOf(n) === 'CATALOG')
      const database = reversed.find((n) => typeOf(n) === 'DATABASE')
      const nodeType = typeOf(node)
      const payload: DataSourceTreeNode = {
        ...node,
        catalogName: catalog?.name,
        databaseName: database?.name,
        tableName: nodeType === 'TABLE' ? node.name : undefined,
      }
      onSelectNode(payload)
    }
  }, [raw, onSelectNode])

  // 滚动到选中功能移除

  return (
    <div style={{ display: 'grid', gap: 8 }}>
      <Space direction="vertical" size="small" style={{ marginBottom: 8 }}>
        <Space>
          <Input.Search allowClear placeholder="搜索节点" size="small" value={searchRaw} onChange={(e) => setSearchRaw(e.target.value)} />
          <Tooltip title="刷新">
            <Button size="small" icon={<ReloadOutlined />} onClick={fetchTree} loading={loading} />
          </Tooltip>
          <Tooltip title="显示服务器">
            <Button
              size="small"
              shape="circle"
              type={displayServer ? 'primary' : 'default'}
              icon={<CloudServerOutlined />}
              onClick={() => setDisplayServer(!displayServer)}
            />
          </Tooltip>
          <Tooltip title="显示表节点">
            <Button
              size="small"
              shape="circle"
              type={displayTable ? 'primary' : 'default'}
              icon={<TableOutlined />}
              onClick={() => setDisplayTable(!displayTable)}
            />
          </Tooltip>
          <Tooltip title="新建数据源">
            <Button size="small" type="primary" icon={<PlusOutlined />} onClick={() => onCreateCatalog?.()} />
          </Tooltip>
        </Space>
      </Space>
      <div style={{ border: '1px solid #f0f0f0', borderRadius: 8, padding: 8, background: '#fafafa' }}>
        <Tree
          showLine
          treeData={treeData as any}
          selectedKeys={selectedKeys}
          onSelect={onSelect}
          virtual
          height={360}
          defaultExpandAll
        />
      </div>
    </div>
  )
}